package it.uniroma1.di.machinelearning;

import java.io.File;
import java.util.Arrays;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import weka.classifiers.Classifier;
import weka.classifiers.evaluation.Evaluation;
import weka.classifiers.trees.J48;
import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;
import weka.filters.Filter;
import weka.filters.unsupervised.attribute.NumericToNominal;

public abstract class ClassifierRunnable implements Runnable{
	
	private static Logger log = Logger.getLogger(ClassifierRunnable.class);
	
	protected static Classifier metaClassifier = new J48();
	protected String trainingPath;
	protected String testPath;
	protected String output;
	protected String outputPath;
	protected Evaluation evaluation;
	private static Instances trainingInstances;
	private static Instances testInstances;
	
	private static Instances prepareInstances(String dataPath) throws Exception{
		DataSource source = new DataSource(dataPath);
		Instances data = source.getDataSet();

		NumericToNominal numericToNominal = new NumericToNominal();
		numericToNominal.setInputFormat(data);
		Instances filteredData = Filter.useFilter(data, numericToNominal);
		filteredData.setClassIndex(filteredData.numAttributes() - 1);
		data.setClassIndex(data.numAttributes() - 1);
		
		return data;
	}
	
	
	@Override
	public void run() {
		try {
			if(trainingInstances==null){
				trainingInstances=prepareInstances(trainingPath);
			}
			
			Classifier classifier = createAndBuildClassifier(trainingInstances);
			//Classifier classifier = createAndBuildClassifier(data);

			if(testInstances==null){
				testInstances=prepareInstances(testPath);
			}
			Evaluation evaluation = new Evaluation(testInstances);
			evaluation.evaluateModel(classifier, testInstances);
			
			this.evaluation=evaluation;
			
			StringBuffer stringBuffer = new StringBuffer();
			stringBuffer.append(classifier.getClass().toString());
			stringBuffer.append(evaluation.toSummaryString(true));
			stringBuffer.append(evaluation.toClassDetailsString());
			stringBuffer.append(evaluation.toMatrixString());
			
			
			
			this.output= stringBuffer.toString();
			log.info(this.output);
			
			FileUtils.writeStringToFile(new File(outputPath), this.output);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public String getOutputPath() {
		return outputPath;
	}


	public void setOutputPath(String outputPath) {
		this.outputPath = outputPath;
	}


	public String getTrainingPath() {
		return trainingPath;
	}


	public void setTrainingPath(String trainingPath) {
		this.trainingPath = trainingPath;
	}


	public String getTestPath() {
		return testPath;
	}


	public void setTestPath(String testPath) {
		this.testPath = testPath;
	}


	public String getOutput() {
		return output;
	}


	public void setOutput(String output) {
		this.output = output;
	}


	public Evaluation getEvaluation(){
		return evaluation;
	}
	
	public abstract Classifier createAndBuildClassifier(Instances instances)
			throws Exception;
}
